package com.scs.application.modules.msg.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.core.msg.domain.*;
import com.scs.application.core.msg.enums.ReceiverType;
import com.scs.application.core.utils.Exceptions;
import com.scs.application.core.utils.IPUtils;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.modules.msg.entity.PushedRecord;
import com.scs.application.modules.msg.entity.Scene;
import com.scs.application.modules.msg.entity.Template;
import com.scs.application.modules.msg.provider.BuildMessageProvider;
import com.scs.application.modules.msg.provider.SendMessageProvider;
import com.scs.application.modules.msg.service.PushedRecordService;
import com.scs.application.modules.msg.service.SceneService;
import com.scs.application.modules.msg.service.TemplateService;
import com.scs.application.modules.upms.request.UserQueryRequest;
import com.scs.application.modules.upms.service.UserService;
import com.scs.application.modules.upms.vo.UserVO;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * @Description:
 */
@Component
@Slf4j
public class SceneMessageHandler {

    @Autowired
    private SceneService sceneService;

    @Autowired
    private TemplateService templateService;

    @Autowired
    private UserService userService;

    @Autowired
    private PushedRecordService pushedRecordService;

    private List<SendMessageProvider> providers;

    private List<BuildMessageProvider> buildProviders;

    private List<RawMessage> messageList = Lists.newArrayList(new SmsMessage(), new PCMessage(), new WechatMessage(), new EmailMessage());

    @Autowired
    public void setProviders(List<SendMessageProvider> providers) {
        this.providers = providers;
    }

    @Autowired
    public void setBuildProviders(List<BuildMessageProvider> providers) {
        this.buildProviders = providers;
    }

    public void handle(SceneMessage sceneMessage) {

        // 获取场景定义
        Scene scene = sceneService.getOne(Wrappers.<Scene>query().eq("code", sceneMessage.getSceneCode()));
        if (scene == null) {
            log.info("场景消息{}发送失败，未找到场景定义，消息内容：{}", sceneMessage.getSceneCode(), JSON.toJSONString(sceneMessage));
            return;
        }
        if (StringUtils.isBlank(sceneMessage.getReceiver()) && sceneMessage.getReceiverType() != ReceiverType.ALL) {
            log.info("场景消息{}发送失败，接收人参数错误，消息内容：{}", sceneMessage.getSceneCode(), JSON.toJSONString(sceneMessage));
            return;
        }

        List<RawMessage> messages = buildMessage(sceneMessage, scene);
        if(messages.size() == 0){
            log.info("场景消息{}发送失败，可能没有进行消息定义，消息内容：{}", sceneMessage.getSceneCode(), JSON.toJSONString(sceneMessage));
            return;
        }

        for (RawMessage message : messages) {
            for (SendMessageProvider handler : providers) {
                if (!handler.support(message.getClass())) {
                    continue;
                }

                Exception ex = null;
                try {
                    if (handler.check(message)) {

                    }
                    handler.send(message);
                    onSuccess(message);
                } catch (Exception e) {
                    onError(message, e);
                    ex = e;
                } finally {
                    onComplete(sceneMessage, message, ex);
                }
            }
        }
    }


    protected void onSuccess(RawMessage msg) {

    }

    protected void onError(RawMessage msg, Exception e) {
        e.printStackTrace();
        // 重发
    }

    protected void onComplete(SceneMessage sceneMessage, RawMessage msg, Exception e) {

        String exceptionMsg = null;
        if (e != null) {
            if (e.getCause() == null) {
                exceptionMsg = e.getMessage();
            } else {
                exceptionMsg = Exceptions.getStackTraceAsString(e);
            }
        }

        PushedRecord pushedRecord = new PushedRecord();
        pushedRecord.setMsgType(msg.getMessageType().name())
                .setReceiver(sceneMessage.getReceiver())
                .setSceneCode(sceneMessage.getSceneCode())
                .setParams(sceneMessage.getParams() != null ? null : null)
                .setIsSuccess(e == null ? GlobalConsts.YES : GlobalConsts.NO)
                .setExceptionMsg(exceptionMsg)
                .setBizType(sceneMessage.getBizType())
                .setBizKey(sceneMessage.getBizKey())
                .setGmtCreate(new Date())
        ;

        for (SendMessageProvider handler : providers) {
            if (handler.support(msg.getClass())) {
                pushedRecord = handler.getPushedRecord(pushedRecord, msg);
                pushedRecord.setPushedIp(IPUtils.getLocalIp());
                break;
            }
        }

        try {
            pushedRecordService.saveCascadeById(pushedRecord);
        } catch (Exception ex) {
            log.error("已推送消息记录保存失败", ex);
        }
    }

    private List<RawMessage> buildMessage(SceneMessage msg, Scene scene) {

        JSONObject defines = scene.getDefines();
        Set<String> keySet = defines.keySet();

        List<RawMessage> messages = new ArrayList<>();
        List<UserVO> userVOList = new ArrayList<>();
        UserQueryRequest request = new UserQueryRequest();

        if (msg.getReceiverType() == ReceiverType.ALL) {
            userVOList = userService.list(request);
        } else if (msg.getReceiverType() == ReceiverType.USER) {
            request.setLoginKey(msg.getReceiver());
            userVOList = userService.list(request);
        } else if (msg.getReceiverType() == ReceiverType.OFFICE) {
            request.setOfficeId(msg.getReceiver());
            userVOList = userService.list(request);
        }

        if (userVOList == null || userVOList.size() == 0) {
            log.info("场景消息发送失败，未找到用户[{}]信息", msg.getReceiver());
            return messages;
        }

        for (String key : keySet) {
            Template template = templateService.getById(defines.getString(key));
            if (template == null) {
                continue;
            }

            RawMessage message = null;
            for (RawMessage rawMessage : messageList) {
                if (rawMessage.isSupport(key)) {
                    message = rawMessage;
                    break;
                }
            }

            if (message == null) {
                continue;
            }
            for (BuildMessageProvider handler : buildProviders) {
                if (handler.support(message.getClass())) {
                    messages.addAll(handler.messagesBuild(userVOList, template, msg));
                    break;
                }
            }
        }
        return messages;
    }

}
